-
Notifications
You must be signed in to change notification settings - Fork 15
Conversation
63958f1
to
d58d4f9
Compare
…s to using the RPC API
…prettify DebugPage and Logging
4667d32
to
36fd6b5
Compare
@CodiumAI-Agent /review |
PR Analysis
PR Feedback
How to use
|
@CodiumAI-Agent /improve --extended |
src/main/cli/cli.ts
Outdated
|
||
cli.on('exit', async (code, signal) => { | ||
logger.info({ subCommand, code, signal }, `CLI excited`); | ||
|
||
onExit(code, signal); | ||
resolveRunning(); | ||
cli = null; | ||
|
||
try { | ||
await readFromDatabaseAndUpdateState(); | ||
} finally { | ||
onExit(code, signal); | ||
resolveRunning(); | ||
} | ||
}); | ||
|
||
[cli.stderr, cli.stdout].forEach((stream) => { | ||
stream.setEncoding('utf8'); | ||
stream.on('data', (data: string) => { | ||
onStdOut(data); | ||
|
||
const logs = getLinesOfString(data) | ||
.map((logText) => { | ||
logger.debug( | ||
{ subCommand, logText: logText.trim() }, | ||
'Received stdout from cli process' | ||
); | ||
|
||
try { | ||
return JSON.parse(logText); | ||
} catch (err) { | ||
logger.debug( | ||
{ | ||
subCommand, | ||
logText, | ||
err, | ||
}, | ||
'Failed to parse CLI log' | ||
); | ||
} | ||
return null; | ||
}) | ||
.filter(isCliLog); | ||
logger.debug({ subCommand, data }, `CLI stdout`); | ||
const logs = getLogsFromRawFileString(data); | ||
|
||
onLog(logs); | ||
|
||
readFromDatabaseAndUpdateState(); | ||
}); | ||
}); | ||
} catch (e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider handling the error in the catch block at line 154. Currently, the error is caught but not handled, which could lead to unexpected behavior.
cli.on('exit', async (code, signal) => { | |
logger.info({ subCommand, code, signal }, `CLI excited`); | |
onExit(code, signal); | |
resolveRunning(); | |
cli = null; | |
try { | |
await readFromDatabaseAndUpdateState(); | |
} finally { | |
onExit(code, signal); | |
resolveRunning(); | |
} | |
}); | |
[cli.stderr, cli.stdout].forEach((stream) => { | |
stream.setEncoding('utf8'); | |
stream.on('data', (data: string) => { | |
onStdOut(data); | |
const logs = getLinesOfString(data) | |
.map((logText) => { | |
logger.debug( | |
{ subCommand, logText: logText.trim() }, | |
'Received stdout from cli process' | |
); | |
try { | |
return JSON.parse(logText); | |
} catch (err) { | |
logger.debug( | |
{ | |
subCommand, | |
logText, | |
err, | |
}, | |
'Failed to parse CLI log' | |
); | |
} | |
return null; | |
}) | |
.filter(isCliLog); | |
logger.debug({ subCommand, data }, `CLI stdout`); | |
const logs = getLogsFromRawFileString(data); | |
onLog(logs); | |
readFromDatabaseAndUpdateState(); | |
}); | |
}); | |
} catch (e) { | |
try { | |
... | |
} catch (e) { | |
logger.error(`Error occurred: ${e.message}`); | |
} |
src/main/cli/cli.ts
Outdated
export async function startRPC() { | ||
await spawnSubcommand( | ||
'start-daemon', | ||
{ | ||
'server-address': `${RPC_BIND_HOST}:${RPC_BIND_PORT}`, | ||
}, | ||
(logs) => { | ||
store.dispatch(rpcAddLogs(logs)); | ||
RPC_LOG_EVENT_EMITTER.emit(logs); | ||
}, | ||
(exitCode, exitSignal) => { | ||
store.dispatch(rpcProcessExited({ exitCode, exitSignal })); | ||
logger.error('RPC server has stopped'); | ||
}, | ||
(text) => { | ||
store.dispatch(rpcAppendStdOut(text)); | ||
} | ||
); | ||
store.dispatch(rpcInitiate()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider adding error handling for the async function 'startRPC' at line 166. Currently, if an error occurs during the execution of 'spawnSubcommand', it will not be caught and could lead to unexpected behavior.
export async function startRPC() { | |
await spawnSubcommand( | |
'start-daemon', | |
{ | |
'server-address': `${RPC_BIND_HOST}:${RPC_BIND_PORT}`, | |
}, | |
(logs) => { | |
store.dispatch(rpcAddLogs(logs)); | |
RPC_LOG_EVENT_EMITTER.emit(logs); | |
}, | |
(exitCode, exitSignal) => { | |
store.dispatch(rpcProcessExited({ exitCode, exitSignal })); | |
logger.error('RPC server has stopped'); | |
}, | |
(text) => { | |
store.dispatch(rpcAppendStdOut(text)); | |
} | |
); | |
store.dispatch(rpcInitiate()); | |
} | |
export async function startRPC() { | |
try { | |
await spawnSubcommand(...); | |
... | |
} catch (e) { | |
logger.error(`Error occurred: ${e.message}`); | |
} | |
} |
src/main/cli/dirs.ts
Outdated
export default async function getSavedLogsOfSwapId( | ||
swapId: string | ||
): Promise<CliLog[]> { | ||
const logsFile = await getCliLogFile(); | ||
const fileData = await getFileData(logsFile); | ||
const allLogs = getLogsFromRawFileString(fileData); | ||
|
||
return allLogs.filter((log) => getCliLogSpanSwapId(log) === swapId); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider adding error handling for the async function 'getSavedLogsOfSwapId' at line 128. Currently, if an error occurs during the execution of 'getCliLogFile' or 'getFileData', it will not be caught and could lead to unexpected behavior.
export default async function getSavedLogsOfSwapId( | |
swapId: string | |
): Promise<CliLog[]> { | |
const logsFile = await getCliLogFile(); | |
const fileData = await getFileData(logsFile); | |
const allLogs = getLogsFromRawFileString(fileData); | |
return allLogs.filter((log) => getCliLogSpanSwapId(log) === swapId); | |
} | |
export default async function getSavedLogsOfSwapId(swapId: string): Promise<CliLog[]> { | |
try { | |
const logsFile = await getCliLogFile(); | |
const fileData = await getFileData(logsFile); | |
... | |
} catch (e) { | |
logger.error(`Error occurred: ${e.message}`); | |
} | |
} |
src/main/cli/rpc.ts
Outdated
export async function checkBitcoinBalance() { | ||
const response = await makeRpcRequest<BalanceBitcoinResponse>( | ||
RpcMethod.GET_BTC_BALANCE, | ||
{} | ||
); | ||
store.dispatch(rpcSetBalance(response.balance)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider adding error handling for the async function 'checkBitcoinBalance' at line 179. Currently, if an error occurs during the execution of 'makeRpcRequest', it will not be caught and could lead to unexpected behavior.
export async function checkBitcoinBalance() { | |
const response = await makeRpcRequest<BalanceBitcoinResponse>( | |
RpcMethod.GET_BTC_BALANCE, | |
{} | |
); | |
store.dispatch(rpcSetBalance(response.balance)); | |
} | |
export async function checkBitcoinBalance() { | |
try { | |
const response = await makeRpcRequest<BalanceBitcoinResponse>(RpcMethod.GET_BTC_BALANCE, {}); | |
... | |
} catch (e) { | |
logger.error(`Error occurred: ${e.message}`); | |
} | |
} |
src/main/cli/rpc.ts
Outdated
export async function withdrawAllBitcoin(address: string) { | ||
store.dispatch(rpcResetWithdrawTxId()); | ||
const response = await makeRpcRequest<WithdrawBitcoinResponse>( | ||
RpcMethod.WITHDRAW_BTC, | ||
{ | ||
address, | ||
} | ||
); | ||
store.dispatch(rpcSetWithdrawTxId(response.txid)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider adding error handling for the async function 'withdrawAllBitcoin' at line 187. Currently, if an error occurs during the execution of 'makeRpcRequest', it will not be caught and could lead to unexpected behavior.
export async function withdrawAllBitcoin(address: string) { | |
store.dispatch(rpcResetWithdrawTxId()); | |
const response = await makeRpcRequest<WithdrawBitcoinResponse>( | |
RpcMethod.WITHDRAW_BTC, | |
{ | |
address, | |
} | |
); | |
store.dispatch(rpcSetWithdrawTxId(response.txid)); | |
} | |
export async function withdrawAllBitcoin(address: string) { | |
try { | |
store.dispatch(rpcResetWithdrawTxId()); | |
const response = await makeRpcRequest<WithdrawBitcoinResponse>(RpcMethod.WITHDRAW_BTC, {address}); | |
... | |
} catch (e) { | |
logger.error(`Error occurred: ${e.message}`); | |
} | |
} |
export async function getSwapInfo(swapId: string) { | ||
return makeRpcRequest<GetSwapInfoResponse>(RpcMethod.GET_SWAP_INFO, { | ||
swap_id: swapId, | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider adding error handling for the async function 'getSwapInfo' at line 198. Currently, if an error occurs during the execution of 'makeRpcRequest', it will not be caught and could lead to unexpected behavior.
export async function getSwapInfo(swapId: string) { | |
return makeRpcRequest<GetSwapInfoResponse>(RpcMethod.GET_SWAP_INFO, { | |
swap_id: swapId, | |
}); | |
} | |
export async function getSwapInfo(swapId: string) { | |
try { | |
return makeRpcRequest<GetSwapInfoResponse>(RpcMethod.GET_SWAP_INFO, {swap_id: swapId}); | |
} catch (e) { | |
logger.error(`Error occurred: ${e.message}`); | |
} | |
} |
src/main/cli/rpc.ts
Outdated
export async function buyXmr( | ||
redeemAddress: string, | ||
refundAddress: string, | ||
provider: Provider | ||
) { | ||
const { swapId } = await makeRpcRequest<BuyXmrResponse>( | ||
RpcMethod.BUY_XMR, | ||
{ | ||
bitcoin_change_address: refundAddress, | ||
monero_receive_address: redeemAddress, | ||
seller: providerToConcatenatedMultiAddr(provider), | ||
}, | ||
(logs) => { | ||
store.dispatch( | ||
swapAddLog({ | ||
logs, | ||
isFromRestore: false, | ||
}) | ||
); | ||
}, | ||
true | ||
); | ||
|
||
store.dispatch( | ||
swapInitiate({ | ||
provider, | ||
spawnType: SwapSpawnType.INIT, | ||
swapId, | ||
}) | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider adding error handling for the async function 'buyXmr' at line 215. Currently, if an error occurs during the execution of 'makeRpcRequest', it will not be caught and could lead to unexpected behavior.
export async function buyXmr( | |
redeemAddress: string, | |
refundAddress: string, | |
provider: Provider | |
) { | |
const { swapId } = await makeRpcRequest<BuyXmrResponse>( | |
RpcMethod.BUY_XMR, | |
{ | |
bitcoin_change_address: refundAddress, | |
monero_receive_address: redeemAddress, | |
seller: providerToConcatenatedMultiAddr(provider), | |
}, | |
(logs) => { | |
store.dispatch( | |
swapAddLog({ | |
logs, | |
isFromRestore: false, | |
}) | |
); | |
}, | |
true | |
); | |
store.dispatch( | |
swapInitiate({ | |
provider, | |
spawnType: SwapSpawnType.INIT, | |
swapId, | |
}) | |
); | |
} | |
export async function buyXmr(redeemAddress: string, refundAddress: string, provider: Provider) { | |
try { | |
const { swapId } = await makeRpcRequest<BuyXmrResponse>(RpcMethod.BUY_XMR, {...}); | |
... | |
} catch (e) { | |
logger.error(`Error occurred: ${e.message}`); | |
} | |
} |
src/main/cli/rpc.ts
Outdated
export async function cancelRefundSwap(swapId: string) { | ||
const swapInfo = await getSwapInfo(swapId); | ||
const previousLogs = await getSavedLogsOfSwapId(swapId); | ||
|
||
store.dispatch( | ||
swapInitiate({ | ||
provider: providerFromGetSellerResponse(swapInfo.seller), | ||
spawnType: SwapSpawnType.CANCEL_REFUND, | ||
swapId, | ||
}) | ||
); | ||
|
||
store.dispatch( | ||
swapAddLog({ | ||
logs: previousLogs, | ||
isFromRestore: true, | ||
}) | ||
); | ||
|
||
await makeRpcRequest( | ||
RpcMethod.CANCEL_REFUND_SWAP, | ||
{ | ||
swap_id: swapId, | ||
}, | ||
(logs) => { | ||
store.dispatch( | ||
swapAddLog({ | ||
logs, | ||
isFromRestore: false, | ||
}) | ||
); | ||
}, | ||
true | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider adding error handling for the async function 'cancelRefundSwap' at line 247. Currently, if an error occurs during the execution of 'getSwapInfo', 'getSavedLogsOfSwapId' or 'makeRpcRequest', it will not be caught and could lead to unexpected behavior.
export async function cancelRefundSwap(swapId: string) { | |
const swapInfo = await getSwapInfo(swapId); | |
const previousLogs = await getSavedLogsOfSwapId(swapId); | |
store.dispatch( | |
swapInitiate({ | |
provider: providerFromGetSellerResponse(swapInfo.seller), | |
spawnType: SwapSpawnType.CANCEL_REFUND, | |
swapId, | |
}) | |
); | |
store.dispatch( | |
swapAddLog({ | |
logs: previousLogs, | |
isFromRestore: true, | |
}) | |
); | |
await makeRpcRequest( | |
RpcMethod.CANCEL_REFUND_SWAP, | |
{ | |
swap_id: swapId, | |
}, | |
(logs) => { | |
store.dispatch( | |
swapAddLog({ | |
logs, | |
isFromRestore: false, | |
}) | |
); | |
}, | |
true | |
); | |
} | |
export async function cancelRefundSwap(swapId: string) { | |
try { | |
const swapInfo = await getSwapInfo(swapId); | |
const previousLogs = await getSavedLogsOfSwapId(swapId); | |
... | |
} catch (e) { | |
logger.error(`Error occurred: ${e.message}`); | |
} | |
} |
src/main/main.ts
Outdated
.whenReady() | ||
.then(async () => { | ||
createWindow(); | ||
registerIpcHandlers(); | ||
initSocket(); | ||
watchDatabase(); | ||
spawnBalanceCheck(); | ||
watchElectrumTransactions(); | ||
watchLogs(); | ||
initStats(); | ||
startRPC(); | ||
|
||
setInterval(() => { | ||
getRawSwapInfos(); | ||
}, 1000 * 20); | ||
|
||
return 0; | ||
}) | ||
.catch((e) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider using a more robust error handling strategy. Currently, if an error occurs during the execution of the 'whenReady' function, the error is simply logged and the execution continues. This might lead to unexpected behavior later in the execution. Consider throwing the error or handling it in a way that prevents further execution in case of a critical failure.
.whenReady() | |
.then(async () => { | |
createWindow(); | |
registerIpcHandlers(); | |
initSocket(); | |
watchDatabase(); | |
spawnBalanceCheck(); | |
watchElectrumTransactions(); | |
watchLogs(); | |
initStats(); | |
startRPC(); | |
setInterval(() => { | |
getRawSwapInfos(); | |
}, 1000 * 20); | |
return 0; | |
}) | |
.catch((e) => | |
try { | |
await app.whenReady(); | |
createWindow(); | |
initSocket(); | |
startRPC(); | |
setInterval(() => { | |
getRawSwapInfos(); | |
}, 1000 * 20); | |
} catch (e) { | |
logger.error( | |
{ error: e.toString() }, | |
'Failed to initialize application' | |
); | |
throw e; | |
} |
src/main/main.ts
Outdated
export function sendSnackbarAlertToRenderer( | ||
message: string, | ||
variant: string, | ||
autoHideDuration: number | null, | ||
key: string | null | ||
) { | ||
function send() { | ||
logger.debug( | ||
{ message, variant, autoHideDuration, key }, | ||
'Attempting to send snackbar alert to renderer' | ||
); | ||
if (mainWindow) { | ||
if ( | ||
mainWindow.webContents.isDestroyed() || | ||
mainWindow.webContents.isLoading() | ||
) { | ||
logger.debug( | ||
'Main window is loading, waiting for it to finish before sending snackbar alert' | ||
); | ||
mainWindow.webContents.once('did-finish-load', () => | ||
setTimeout(send, 5000) | ||
); | ||
} else { | ||
logger.debug( | ||
{ message, variant, autoHideDuration, key }, | ||
'Sending snackbar alert to renderer' | ||
); | ||
mainWindow?.webContents.send( | ||
'display-snackbar-alert', | ||
message, | ||
variant, | ||
autoHideDuration, | ||
key | ||
); | ||
} | ||
} else { | ||
setTimeout(send, 1000); | ||
} | ||
} | ||
send(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider using a more robust error handling strategy. Currently, if an error occurs during the execution of the 'sendSnackbarAlertToRenderer' function, the error is simply logged and the execution continues. This might lead to unexpected behavior later in the execution. Consider throwing the error or handling it in a way that prevents further execution in case of a critical failure.
export function sendSnackbarAlertToRenderer( | |
message: string, | |
variant: string, | |
autoHideDuration: number | null, | |
key: string | null | |
) { | |
function send() { | |
logger.debug( | |
{ message, variant, autoHideDuration, key }, | |
'Attempting to send snackbar alert to renderer' | |
); | |
if (mainWindow) { | |
if ( | |
mainWindow.webContents.isDestroyed() || | |
mainWindow.webContents.isLoading() | |
) { | |
logger.debug( | |
'Main window is loading, waiting for it to finish before sending snackbar alert' | |
); | |
mainWindow.webContents.once('did-finish-load', () => | |
setTimeout(send, 5000) | |
); | |
} else { | |
logger.debug( | |
{ message, variant, autoHideDuration, key }, | |
'Sending snackbar alert to renderer' | |
); | |
mainWindow?.webContents.send( | |
'display-snackbar-alert', | |
message, | |
variant, | |
autoHideDuration, | |
key | |
); | |
} | |
} else { | |
setTimeout(send, 1000); | |
} | |
} | |
send(); | |
} | |
export function sendSnackbarAlertToRenderer( | |
message: string, | |
variant: string, | |
autoHideDuration: number | null, | |
key: string | null | |
) { | |
function send() { | |
logger.debug( | |
{ message, variant, autoHideDuration, key }, | |
'Attempting to send snackbar alert to renderer' | |
); | |
if (mainWindow) { | |
if ( | |
mainWindow.webContents.isDestroyed() || | |
mainWindow.webContents.isLoading() | |
) { | |
logger.debug( | |
'Main window is loading, waiting for it to finish before sending snackbar alert' | |
); | |
mainWindow.webContents.once('did-finish-load', () => | |
setTimeout(send, 5000) | |
); | |
} else { | |
logger.debug( | |
{ message, variant, autoHideDuration, key }, | |
'Sending snackbar alert to renderer' | |
); | |
try { | |
mainWindow?.webContents.send( | |
'display-snackbar-alert', | |
message, | |
variant, | |
autoHideDuration, | |
key | |
); | |
} catch (e) { | |
logger.error( | |
{ error: e.toString() }, | |
'Failed to send snackbar alert to renderer' | |
); | |
throw e; | |
} | |
} | |
} else { | |
setTimeout(send, 1000); | |
} | |
} | |
send(); | |
} |
src/models/databaseModel.ts
Outdated
export function getSwapTxFees(swap: GetSwapInfoResponse): number { | ||
// TODO | ||
return 124; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: The function getSwapTxFees
has a TODO comment and returns a hardcoded value. It would be better to implement the function or, if it's not possible at the moment, throw an error or return a more meaningful default value.
export function getSwapTxFees(swap: GetSwapInfoResponse): number { | |
// TODO | |
return 124; | |
} | |
export function getSwapTxFees(swap: GetSwapInfoResponse): number { | |
throw new Error('Function getSwapTxFees not implemented yet'); | |
} |
src/models/databaseModel.ts
Outdated
export function getSwapExchangeRate(swap: GetSwapInfoResponse): number { | ||
const btcAmount = getSwapBtcAmount(swap); | ||
const xmrAmount = getSwapXmrAmount(swap); | ||
|
||
return btcAmount / xmrAmount; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: The function getSwapExchangeRate
doesn't handle the case where xmrAmount
is 0, which would cause a division by zero error. It would be better to add a check for this case.
export function getSwapExchangeRate(swap: GetSwapInfoResponse): number { | |
const btcAmount = getSwapBtcAmount(swap); | |
const xmrAmount = getSwapXmrAmount(swap); | |
return btcAmount / xmrAmount; | |
} | |
export function getSwapExchangeRate(swap: GetSwapInfoResponse): number { | |
const btcAmount = getSwapBtcAmount(swap); | |
const xmrAmount = getSwapXmrAmount(swap); | |
if (xmrAmount === 0) { | |
throw new Error('XMR amount is zero, cannot calculate exchange rate'); | |
} | |
return btcAmount / xmrAmount; | |
} |
export enum RpcMethod { | ||
GET_BTC_BALANCE = 'get_bitcoin_balance', | ||
WITHDRAW_BTC = 'withdraw_btc', | ||
BUY_XMR = 'buy_xmr', | ||
RESUME_SWAP = 'resume_swap', | ||
LIST_SELLERS = 'list_sellers', | ||
CANCEL_REFUND_SWAP = 'cancel_refund_swap', | ||
GET_SWAP_INFO = 'get_swap_info', | ||
SUSPEND_CURRENT_SWAP = 'suspend_current_swap', | ||
GET_HISTORY = 'get_history', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider using a more descriptive name for the enum RpcMethod
. The current name is not very descriptive of what the enum represents. A more descriptive name could be RpcSwapMethods
or RpcSwapActions
.
export enum RpcMethod { | |
GET_BTC_BALANCE = 'get_bitcoin_balance', | |
WITHDRAW_BTC = 'withdraw_btc', | |
BUY_XMR = 'buy_xmr', | |
RESUME_SWAP = 'resume_swap', | |
LIST_SELLERS = 'list_sellers', | |
CANCEL_REFUND_SWAP = 'cancel_refund_swap', | |
GET_SWAP_INFO = 'get_swap_info', | |
SUSPEND_CURRENT_SWAP = 'suspend_current_swap', | |
GET_HISTORY = 'get_history', | |
export enum RpcSwapMethods { | |
GET_BTC_BALANCE = 'get_bitcoin_balance', | |
WITHDRAW_BTC = 'withdraw_btc', | |
BUY_XMR = 'buy_xmr', | |
RESUME_SWAP = 'resume_swap', | |
LIST_SELLERS = 'list_sellers', | |
CANCEL_REFUND_SWAP = 'cancel_refund_swap', | |
GET_SWAP_INFO = 'get_swap_info', | |
SUSPEND_CURRENT_SWAP = 'suspend_current_swap', | |
GET_HISTORY = 'get_history', | |
} |
const balance = useAppSelector((s) => s.rpc.state.balance); | ||
|
||
if (balance == null || balance <= 0) { | ||
return <></>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Consider adding error handling for the case when balance
is null
. Currently, the code simply returns an empty fragment when balance
is null
or less than or equal to 0. It would be more user-friendly to display a message indicating that the balance could not be retrieved.
const balance = useAppSelector((s) => s.rpc.state.balance); | |
if (balance == null || balance <= 0) { | |
return <></>; | |
const balance = useAppSelector((s) => s.rpc.state.balance); | |
if (balance == null || balance <= 0) { | |
return <Alert severity="error">Could not retrieve balance</Alert>; | |
} |
57ddb9a
to
d7b56b3
Compare
This also changes the rpcSlice to store parsed logs
No description provided.